package com.jingfu.configuration.shiro;

import com.jingfu.Service.UserService;
import com.jingfu.common.AccountStatusException;
import com.jingfu.common.BadRequestException;
import com.jingfu.common.ErrorCode;
import com.jingfu.dto.UserDetail;
import com.jingfu.mapper.SysUserMapper;
import com.jingfu.pojo.SysPower;
import com.jingfu.pojo.SysUser;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author jingfuu@163.com
 * @version v1.0
 * @date 2022/1/7 上午11:06
 **/
@Component
@Slf4j
public class ShiroRealm extends AuthorizingRealm implements ApplicationContextAware {

    /**
     * 必须加@Lazy注解，否则Realm实现中Service对象会提前被加载，
     * 保证Service实际初始化的时候会被BeanPostProcessor拦截，创建具有事务功能的代理对象
     */
    @Autowired
    @Lazy
    UserService userService;

    @Autowired
    SysUserMapper sysUserMapper;




    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        if (principals == null) {
            throw new AuthorizationException("用户凭证不能为空");
        } else {
            String username = (String)this.getAvailablePrincipal(principals);
            Set<String> roleNames = null;
            Set permissions = null;

            try {
                UserDetail userDetail =  userService.getUserDetail(username);
                //获取用户所有角色
                roleNames = userDetail.getRoles().stream().map(item->item.getRoleCode()).collect(Collectors.toSet());
                //获取所有权限（菜单、按钮）
                permissions = userDetail.getPermissions();
            } catch (Exception e) {
                String message = "获取授权信息失败";
                if (log.isErrorEnabled()) {
                    log.error(message, e);
                }

                throw new AuthorizationException(message, e);
            }
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roleNames);
            info.setStringPermissions(permissions);
            return info;
        }
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken upToken = (UsernamePasswordToken)token;
        String username = upToken.getUsername();
        if (username == null) {
            throw new AccountException("Null usernames are not allowed by this realm.");
        }
        SimpleAuthenticationInfo info = null;
        UserDetail userDetail =  userService.getUserDetail(username);
        if (Objects.isNull(userDetail)) {
            throw new AccountException("user does not exist");
        }
        if ("0".equals(userDetail.getEnable())) {
            throw new AccountStatusException();
        }
        info = new SimpleAuthenticationInfo(username, userDetail.getPassword().toCharArray(), this.getName());
        return info;
    }

    @Override
    public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
        super.setCredentialsMatcher(credentialsMatcher);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        super.setCredentialsMatcher((CredentialsMatcher) applicationContext.getBean("credentialsMatcher"));
    }
}
